<?php

namespace app\core;

use Exception;
use Swoole\Http\Request;
use Swoole\Http\Response;
use app\core\Request as appRequest;
use app\core\ExceptionHandler;
use app\common\Show;
use app\core\Container\Reflection\ReflectionContainer;
use Swoole\ExitException;
use Throwable;
use app\core\DB\Test\DBPoolContext;
use app\core\Log;
use Swoole\Coroutine;
use Swoole\Timer;

class Route
{
    public static $routes=[
        'GET'=>[],
        'POST'=>[]
    ];
    public static function init(){
        $fileLists=scandir(DIR.'/controller');
       
        $routes=static::$routes;
        $namedAttributes=[];
        $phpFiles=preg_replace("/.php/",'',$fileLists);
        for($i=2;$i<count($phpFiles);$i++){
            $fileName=$phpFiles[$i];
            $className='app\\controller\\'.$fileName;
           
            $object= ReflectionContainer::getClassReflection($className);
           
           
             foreach($object->getMethods() as $k=>$v){
                $name=$v->name;
               
                if(!empty($v->getAttributes())){
                   
                   foreach($v->getAttributes() as $attrKey=>$attrItem){
                        $attrNames=array_reverse(explode('\\',$attrItem->getName()));
                       

                        $attributeName=strtolower($attrNames[2]);
                        $namedAttributes[$name][$fileName]['attributes'][$attributeName][]=$attrItem;
                        $namedAttributes[$name][$fileName]['className']=$className;
                        $namedAttributes[$name][$fileName]['method']=$name;
                  
                   }
                }
             }
        }
     
        // print_r($namedAttributes);
        foreach($namedAttributes as $attrKey=>$attrItem){
            
            foreach($attrItem as $aiKey=>$aiItem){
              
                $route=$aiItem['attributes']['route'][0];
                $args=$route->getArguments();
             
                $specifiedMethod=strtoupper($args['method']);
                $specifiedUrl=$args['url'];
                $routes[$specifiedMethod][$specifiedUrl]=[
                    'route'=>$route,
                    'method'=>$aiItem['method'],
                    'className'=>$aiItem['className']
                ];
                if(array_key_exists('validate',$aiItem['attributes'])){

                    $routes[$specifiedMethod][$specifiedUrl]['validate']=$aiItem['attributes']['validate'];
                }
            }
        }
        // Log::info($routes);
        static::$routes=$routes;
      
    }
    public static function run(Request $request, Response $response)
    {
        
        $resp = '';
            try {
                $uri= explode('/', trim($request->server['request_uri'], '/'));
                $method = strtoupper($request->server['request_method']);
                if(count($uri)<2){
                    throw new Exception("error",204);
                }
                [$head, $action]=$uri;
            
                $specifiedRoute=static::$routes[$method];
            
                if(!array_key_exists($action,$specifiedRoute)){
                    throw new Exception("specified route not exists",500);
                }
                appRequest::init($request);
                $specifiedAction=$specifiedRoute[$action];
            
                $specifiedAction['route']->newInstance();
            
                if(array_key_exists('validate',$specifiedAction)){
                
                    foreach($specifiedAction['validate'] as $k=>$v){
                        $c=$v->newInstance();
                    
                    }
                }
            
                $specifieddMethod=$specifiedAction['method'];
                
                $args=appRequest::param();
            
                $resp= json_encode(ReflectionContainer::getClassReflection($specifiedAction['className'])->newInstance()->{$specifieddMethod}(...$args),JSON_UNESCAPED_UNICODE);
            
                // $resp=json_encode(ReflectionContainer::getMethodReflection($specifiedAction['className'],$specifieddMethod)->invokeArgs(new $specifiedAction['className'],$args),JSON_UNESCAPED_UNICODE);
            
            }
            catch (Throwable $e) {
                
                $code=(int)$e->getCode();
                $resp = json_encode(['message'=>$e->getMessage(),'code'=>$code],JSON_UNESCAPED_UNICODE);
                $response->status(400);
                
            }
            $response->header('Content-Type','application/json;charset=utf-8');
            $response->end($resp);
            
            Coroutine::defer(function(){
                Context::delete();
            });
       
    }
}
